/**
 * 统一错误处理机制
 * 提供统一的错误捕获、处理和上报功能
 */

import { ElMessage, ElNotification } from 'element-plus'
import type { App } from 'vue'

// ==================== 错误类型定义 ====================
export enum ErrorType {
  NETWORK = 'NETWORK',
  API = 'API',
  VALIDATION = 'VALIDATION',
  BUSINESS = 'BUSINESS',
  SYSTEM = 'SYSTEM',
  UNKNOWN = 'UNKNOWN'
}

export interface ErrorInfo {
  type: ErrorType
  code?: string | number
  message: string
  details?: Record<string, unknown>
  stack?: string
  timestamp: number
  url?: string
  userAgent?: string
  userId?: string
}

export interface ErrorHandlerOptions {
  showMessage?: boolean
  showNotification?: boolean
  logToConsole?: boolean
  reportToServer?: boolean
  reportUrl?: string
}

// ==================== 错误处理器类 ====================
class ErrorHandler {
  private options: ErrorHandlerOptions
  private errorQueue: ErrorInfo[] = []
  private isReporting = false

  constructor(options: ErrorHandlerOptions = {}) {
    this.options = {
      showMessage: true,
      showNotification: false,
      logToConsole: true,
      reportToServer: false,
      reportUrl: '/api/errors',
      ...options
    }
  }

  // 处理错误
  handle(error: unknown, type: ErrorType = ErrorType.UNKNOWN, options?: Partial<ErrorHandlerOptions>): void {
    const errorInfo = this.createErrorInfo(error, type)
    const mergedOptions = { ...this.options, ...options }

    // 记录错误
    this.recordError(errorInfo)

    // 控制台输出
    if (mergedOptions.logToConsole) {
      this.logToConsole(errorInfo)
    }

    // 用户提示
    this.showUserMessage(errorInfo, mergedOptions)

    // 服务器上报
    if (mergedOptions.reportToServer) {
      this.reportToServer(errorInfo)
    }
  }

  // 创建错误信息
  private createErrorInfo(error: unknown, type: ErrorType): ErrorInfo {
    const errorInfo: ErrorInfo = {
      type,
      message: this.getErrorMessage(error),
      timestamp: Date.now(),
      url: window.location.href,
      userAgent: navigator.userAgent
    }

    if (error instanceof Error) {
      errorInfo.code = (error as Error & { code?: string | number }).code
      errorInfo.stack = error.stack
      errorInfo.details = {
        name: error.name,
        message: error.message
      }
    } else if (typeof error === 'object' && error !== null) {
      const errorObj = error as Record<string, unknown>
      errorInfo.code = errorObj.code as string | number
      errorInfo.details = errorObj
    } else {
      errorInfo.details = { value: error }
    }

    return errorInfo
  }

  // 获取错误消息
  private getErrorMessage(error: unknown): string {
    if (error instanceof Error) {
      return error.message
    }
    if (typeof error === 'string') {
      return error
    }
    if (error && typeof error === 'object') {
      const errorObj = error as Record<string, unknown>
      return (errorObj.message as string) || (errorObj.msg as string) || (errorObj.error as string) || '未知错误'
    }
    return '未知错误'
  }

  // 记录错误
  private recordError(errorInfo: ErrorInfo): void {
    this.errorQueue.push(errorInfo)
    
    // 限制队列长度
    if (this.errorQueue.length > 100) {
      this.errorQueue.shift()
    }
  }

  // 控制台输出
  private logToConsole(errorInfo: ErrorInfo): void {
    const { type, message, details, stack } = errorInfo
    
    console.group(`🚨 ${type} Error`)
    console.error('Message:', message)
    if (details) console.error('Details:', details)
    if (stack) console.error('Stack:', stack)
    console.error('Time:', new Date(errorInfo.timestamp).toISOString())
    console.groupEnd()
  }

  // 显示用户消息
  private showUserMessage(errorInfo: ErrorInfo, options: ErrorHandlerOptions): void {
    const { type, message } = errorInfo
    let userMessage = message

    // 根据错误类型调整用户消息
    switch (type) {
      case ErrorType.NETWORK:
        userMessage = '网络连接异常，请检查网络后重试'
        break
      case ErrorType.API:
        userMessage = '服务器响应异常，请稍后重试'
        break
      case ErrorType.VALIDATION:
        userMessage = message // 验证错误直接显示
        break
      case ErrorType.BUSINESS:
        userMessage = message // 业务错误直接显示
        break
      case ErrorType.SYSTEM:
        userMessage = '系统异常，请刷新页面重试'
        break
      default:
        userMessage = '操作失败，请稍后重试'
    }

    if (options.showMessage) {
      ElMessage.error(userMessage)
    }

    if (options.showNotification) {
      ElNotification.error({
        title: '错误提示',
        message: userMessage,
        duration: 5000
      })
    }
  }

  // 服务器上报
  private async reportToServer(errorInfo: ErrorInfo): Promise<void> {
    if (this.isReporting || !this.options.reportUrl) return

    this.isReporting = true
    try {
      await fetch(this.options.reportUrl as string, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(errorInfo)
      })
    } catch (error) {
      console.error('Error reporting failed:', error)
    } finally {
      this.isReporting = false
    }
  }

  // 获取错误队列
  getErrorQueue(): ErrorInfo[] {
    return [...this.errorQueue]
  }

  // 清空错误队列
  clearErrorQueue(): void {
    this.errorQueue = []
  }

  // 更新配置
  updateOptions(options: Partial<ErrorHandlerOptions>): void {
    this.options = { ...this.options, ...options }
  }
}

// ==================== 全局错误处理器实例 ====================
export const errorHandler = new ErrorHandler()

// ==================== 错误处理函数 ====================
export const handleError = (error: unknown, type: ErrorType = ErrorType.UNKNOWN, options?: Partial<ErrorHandlerOptions>) => {
  errorHandler.handle(error, type, options)
}

export const handleApiError = (error: unknown, options?: Partial<ErrorHandlerOptions>) => {
  handleError(error, ErrorType.API, options)
}

export const handleNetworkError = (error: unknown, options?: Partial<ErrorHandlerOptions>) => {
  handleError(error, ErrorType.NETWORK, options)
}

export const handleValidationError = (error: unknown, options?: Partial<ErrorHandlerOptions>) => {
  handleError(error, ErrorType.VALIDATION, options)
}

export const handleBusinessError = (error: unknown, options?: Partial<ErrorHandlerOptions>) => {
  handleError(error, ErrorType.BUSINESS, options)
}

export const handleSystemError = (error: unknown, options?: Partial<ErrorHandlerOptions>) => {
  handleError(error, ErrorType.SYSTEM, options)
}

// ==================== Vue 错误处理设置 ====================
export const setupVueErrorHandler = (app: App) => {
  // Vue 错误处理
  app.config.errorHandler = (err: unknown, instance, info) => {
    console.error('Vue Error:', err, info)
    
    const errorInfo: ErrorInfo = {
      type: ErrorType.SYSTEM,
      message: err instanceof Error ? err.message : String(err),
      details: { info, instance: instance?.$options.name },
      timestamp: Date.now(),
      url: window.location.href,
      userAgent: navigator.userAgent
    }

    errorHandler.handle(errorInfo)
  }

  // 全局未捕获的 Promise 错误
  window.addEventListener('unhandledrejection', (event) => {
    console.error('Unhandled Promise Rejection:', event.reason)
    
    const errorInfo: ErrorInfo = {
      type: ErrorType.SYSTEM,
      message: event.reason instanceof Error ? event.reason.message : String(event.reason),
      details: { reason: event.reason },
      timestamp: Date.now(),
      url: window.location.href,
      userAgent: navigator.userAgent
    }

    errorHandler.handle(errorInfo)
    event.preventDefault()
  })

  // 全局 JavaScript 错误
  window.addEventListener('error', (event) => {
    console.error('JavaScript Error:', event.error)
    
    const errorInfo: ErrorInfo = {
      type: ErrorType.SYSTEM,
      message: event.error?.message || 'JavaScript Error',
      details: { 
        filename: event.filename,
        lineno: event.lineno,
        colno: event.colno,
        error: event.error
      },
      timestamp: Date.now(),
      url: window.location.href,
      userAgent: navigator.userAgent
    }

    errorHandler.handle(errorInfo)
    event.preventDefault()
  })
}

// ==================== 请求错误处理 ====================
export const handleRequestError = (error: unknown) => {
  const errorObj = error as { response?: { status: number; data?: { message?: string } } }
  if (!errorObj.response) {
    // 网络错误
    handleNetworkError(error, {
      showMessage: true,
      showNotification: false
    })
  } else {
    // HTTP 错误
    const { status, data } = errorObj.response
    let errorType = ErrorType.API
    let message = '请求失败'

    switch (status) {
      case 400:
        errorType = ErrorType.VALIDATION
        message = data?.message || '请求参数错误'
        break
      case 401:
        errorType = ErrorType.BUSINESS
        message = '未授权，请重新登录'
        break
      case 403:
        errorType = ErrorType.BUSINESS
        message = '权限不足'
        break
      case 404:
        errorType = ErrorType.API
        message = '请求的资源不存在'
        break
      case 500:
        errorType = ErrorType.API
        message = '服务器内部错误'
        break
      case 502:
      case 503:
      case 504:
        errorType = ErrorType.API
        message = '服务器暂时不可用'
        break
      default:
        message = data?.message || `请求失败 (${status})`
    }

    handleError({ message, code: status }, errorType, {
      showMessage: true,
      showNotification: false
    })
  }
}

// ==================== 错误边界组件 ====================
export const createErrorBoundary = (fallback?: (error: ErrorInfo) => unknown) => {
  return {
    data() {
      return {
        hasError: false,
        error: null as ErrorInfo | null
      }
    },
    errorCaptured(err: unknown, instance: unknown, info: string) {
      const errorInfo: ErrorInfo = {
        type: ErrorType.SYSTEM,
        message: err instanceof Error ? err.message : String(err),
        details: { info, instance: (instance as { $options?: { name?: string } })?.$options?.name },
        timestamp: Date.now(),
        url: window.location.href,
        userAgent: navigator.userAgent
      }

      const self = this as unknown as { hasError: boolean; error: ErrorInfo | null }
      self.hasError = true
      self.error = errorInfo
      errorHandler.handle(errorInfo)

      return false
    },
    render(this: { hasError: boolean; error: ErrorInfo | null; $createElement: Function; $slots: { default?: Function } }) {
      const self = this
      if (self.hasError && self.error) {
        return fallback ? fallback(self.error) : self.$createElement('div', {
          class: 'error-boundary'
        }, [
          self.$createElement('h3', '页面出现错误'),
          self.$createElement('p', self.error.message),
          self.$createElement('button', {
            on: {
              click: () => { 
                self.hasError = false
                self.error = null 
              }
            }
          }, '重试')
        ])
      }
      return self.$slots.default?.()
    }
  }
}

// ==================== 导出 ====================
export default {
  ErrorHandler,
  errorHandler,
  handleError,
  handleApiError,
  handleNetworkError,
  handleValidationError,
  handleBusinessError,
  handleSystemError,
  setupVueErrorHandler,
  handleRequestError,
  createErrorBoundary
}
